#![deny(unsafe_code)]

#[macro_use]
extern crate log;
#[macro_use]
extern crate anyhow;

mod async_mod;
mod connect;
mod message_register;
mod user;

use std::process;
use std::sync::mpsc;

use honeybee::prelude::*;

fn main() {
    daemon_check();

    logger_init().unwrap();

    panic_hook();

    let (shutdown_tx, shutdown_rx) = mpsc::sync_channel(1);

    let shutdown_addr = async_mod::run(shutdown_tx.clone());

    wait_shutdown(shutdown_tx, shutdown_rx, shutdown_addr);

    info!("terminated");

    log::logger().flush();
}

fn wait_shutdown(
    shutdown_tx: mpsc::SyncSender<&'static str>,
    shutdown_rx: mpsc::Receiver<&'static str>,
    shutdown_addr: Addr<ShutdownActor>,
) {
    ctrlc::set_handler(move || {
        info!("receive shutdown signal");
        if let Err(err) = shutdown_tx.send("shutdown signal") {
            error!("set_shutdown_signal err:{}", err);
        }
    })
    .expect("Error setting Ctrl-C handler");

    let mut ctrlc_signal = false;
    loop {
        match shutdown_rx.recv().unwrap() {
            "shutdown signal" => {
                if !ctrlc_signal {
                    ctrlc_signal = true;
                    let _ = shutdown_addr.send(ShutDown);
                }
            }
            "async_main exit" => {
                break;
            }
            _ => {
                break;
            }
        }
    }
}

#[cfg(unix)]
fn daemon_check() {
    use daemonize::Daemonize;
    use std::env;
    if false {
        info!(
            "{} process run as a daemon.",
            env::current_exe()
                .unwrap()
                .file_name()
                .unwrap()
                .to_str()
                .unwrap()
        );
        match Daemonize::new().start() {
            Ok(_) => info!("Success, daemonized"),
            Err(e) => error!("Error, {}", e),
        }
    }
}

#[cfg(windows)]
fn daemon_check() {}

fn panic_hook() {
    use std::panic;
    use std::thread;
    panic::set_hook(Box::new(move |info| {
        honeybee_log::Controller::<LogTargetMap>::new().add_appender(
            module_path!(),
            honeybee_log::Appender::new_console_appender().build(),
        );
        error!(
            "[panic] thread '{}' {}\nbacktrace: {:?}",
            thread::current().name().unwrap_or("<unnamed>"),
            info,
            backtrace::Backtrace::new()
        );
        log::logger().flush();
        process::exit(1);
    }));
}

struct LogTargetMap {}

impl honeybee_log::TargetMapping for LogTargetMap {
    fn map(_target: &str) -> honeybee_log::TargetIndex {
        honeybee_log::TargetIndex::T0
    }
}

fn logger_init() -> Result<(), Box<dyn std::error::Error>> {
    /*let level = {
        if &CONFIG.log.filter == "all" {
            "debug"
        } else {
            &CONFIG.log.filter
        }
    };*/
    let level = "debug";
    let default_log = honeybee_log::name(module_path!())
        .level(level)?
        //.appender(honeybee_log::Appender::new_file_appender(&CONFIG.log.file_path)?.build())
        .appender(honeybee_log::Appender::new_console_appender().build())
        .appender(
            honeybee_log::Appender::new_file_appender("/home/sailing/log/honeybee-robot.log")?
                .build(),
        )
        .build();

    honeybee_log::LogBuilder::<LogTargetMap>::new()
        .add_logger(default_log)
        .init()
}
